#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/fcntl.h>

#define MODULE_NAME  "parll"

#define IOCTL_TYPE 0

#define MINS 1
#define HOURS 2
#define DAYS 3

#define outb_p(value,port)                      \
  __asm__ ("outb %%al,%%dx\n"                   \
           "\tjmp 1f\n"                         \
           "1:\tjmp 1f\n"                       \
           "1:"::"a" (value),"d" (port))

#define inb_p(port) ({                                  \
      unsigned char _v;                                 \
      __asm__ volatile ("inb %%dx,%%al\n"               \
                        "\tjmp 1f\n"                    \
                        "1:\tjmp 1f\n"                  \
                        "1:":"=a" (_v):"d" (port));     \
      _v;                                               \
    })


#define CMOS_READ(addr) ({                      \
      outb_p(0x80|addr,0x70);                   \
      inb_p(0x71);                              \
    })
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)

static int Major = 0;



int parlport_open(struct inode *ino, struct file *filp)
{
  printk("\n parlport open function");
  return 0;
}

int parlport_close(struct inode *ino, struct file *filp)
{
  printk("\n parlport close function");
  return 0;
}

int parlport_ioctl(struct inode *ino, struct file *filp,
     unsigned int ioctl_cmd, unsigned long parm)
{
  //  if(_IOC_TYPE(ioctl_cmd) != IOCTL_TYPE)
  //  {
  //   printk("\n%s wrong ioctl type",MODULE_NAME);
  //   return -1;
  //  }


  struct tm time;
  do {
    time.tm_sec = CMOS_READ(0);
    time.tm_min = CMOS_READ(2);
    time.tm_hour = CMOS_READ(4);
    time.tm_mday = CMOS_READ(7);
    time.tm_mon = CMOS_READ(8)-1;
    time.tm_year = CMOS_READ(9);
  } while (time.tm_sec != CMOS_READ(0));
  printk("%d - %d - %d - %d - %d - %d\n",BCD_TO_BIN(time.tm_year),BCD_TO_BIN(time.tm_mon),BCD_TO_BIN(time.tm_mday),BCD_TO_BIN(time.tm_hour),BCD_TO_BIN(time.tm_min),BCD_TO_BIN(time.tm_sec));

  
  switch(ioctl_cmd)
  {
   case MINS:
     parm =  BCD_TO_BIN(time.tm_min);
     return parm&0xff;

   case HOURS:
     printk(" ========================================= \n");
     printk("%d\n",time.tm_hour);
     printk(" ========================================= \n");
     parm = BCD_TO_BIN(time.tm_hour);     
     return parm&0xff;

   case DAYS:
     parm = BCD_TO_BIN(time.tm_mday);
     return parm&0xff;

  }  //end switch
  return 0;
} //end ioctl

 void release_region(unsigned long start, unsigned long n)
 {
 
 }

void request_region(unsigned long start,unsigned long n, char * name)
{
  
}

struct file_operations parlport_fops = { 
     .open =   parlport_open,
     .ioctl =  parlport_ioctl,
     .release =  parlport_close };


static int parll_init(void)
{
  int retval;

  retval= register_chrdev(Major, MODULE_NAME, &parlport_fops);
  if(retval < 0)
  {
   printk("\n%s: can't register",MODULE_NAME);
   return retval;
  }
  else
  {
   Major=retval;
   printk(" ============== \n");             
   printk("\n%s:registered, Major=%d",MODULE_NAME,Major);
   printk(" ============== \n");
   //   if(request_region(base,3,MODULE_NAME))
   //    printk("\n%s:I/O region busy.",MODULE_NAME);

  }
  return 0;
}

static void parll_cleanup( void )
{
   printk("\n%s:cleanup ",MODULE_NAME);
   //   release_region(base,3);
   unregister_chrdev(Major,MODULE_NAME);
}

module_init(parll_init);
module_exit(parll_cleanup);
